#pragma once

#include<iostream>
#include<cstdlib>
#include<cstring>
#include<unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<pthread.h>
#include"Log.hpp"


#define BACKBLOG 5

class TcpServer{
    private:
        int port;
        int listen_sock;
        static TcpServer* svr;
        
    private:
        TcpServer(int _port) // 构造
            :port(_port),listen_sock(-1)
        {}

        TcpServer(const TcpServer &S)
        {}
        
    public:
        static TcpServer* getinstance(int port)
        {
            static pthread_mutex_t lock=PTHREAD_MUTEX_INITIALIZER;
            if(nullptr==svr)
            {
                pthread_mutex_lock(&lock); // 加锁
                if(nullptr==svr)
                {
                    svr=new TcpServer(port);
                    svr->InitServer();
                }
                pthread_mutex_unlock; // 解锁
            }
            return svr;
        }
        void InitServer() // 初始化
        {
            Socket();
            Bind();
            Listen();
            LOG(INFO,"TcpServer Init success");
        }

        void Socket() // 创建套接字
        {
            listen_sock=socket(AF_INET,SOCK_STREAM,0);
            if(listen_sock<0) // 创建套接字失败
            {
                LOG(FATAL,"create socket failed");
                exit(1);
            }
            // 创建套接字失败可以立即地址复用
            int opt=1;
            setsockopt(listen_sock,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));
            LOG(INFO,"create socket success");
        }
        void Bind() // 绑定套接字
        {
            struct sockaddr_in local;
            memset(&local,0,sizeof(local));

            local.sin_family=AF_INET;
            local.sin_port=htons(port);
            local.sin_addr.s_addr=INADDR_ANY;

            if(bind(listen_sock,(struct sockaddr*)&local,sizeof(local))<0)
            {
                LOG(FATAL,"bind failed");
                exit(2);
            }
            LOG(INFO,"bind success! ");
        }
        void Listen() // 监听套接字
        {
            if(listen(listen_sock,BACKBLOG)<0)
            {
                LOG(FATAL,"listen failed");
                exit(3);
            }
            LOG(INFO,"listen success");
        }

        int Sock()
        {
            return listen_sock;
        }
        
        ~TcpServer() // 析构
        {
            if(listen_sock>0)
            {
                close(listen_sock);
            }
        }
};
TcpServer* TcpServer::svr=nullptr;